'''
copyright: Copyright (C) 2015-2024, Wazuh Inc.

           Created by Wazuh, Inc. <info@wazuh.com>.

           This program is free software; you can redistribute it and/or modify it under the terms of GPLv2

type: integration

brief: Wazuh is able to detect vulnerabilities in the applications installed in agents using the Vulnerability Detector
       module. This software audit is performed through the integration of vulnerability feeds indexed by Redhat,
       Canonical, Debian, Amazon Linux and NVD Database.

components:
    - vulnerability_detector

suite: providers

targets:
    - manager

daemons:
    - wazuh-modulesd
    - wazuh-db
    - wazuh-analysisd

os_platform:
    - linux

os_version:
    - Arch Linux
    - Amazon Linux 2
    - Amazon Linux 1
    - CentOS 8
    - CentOS 7
    - Debian Buster
    - Red Hat 8
    - Ubuntu Focal
    - Ubuntu Bionic

references:
    - https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/index.html
    - https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/vuln-detector.html#provider

tags:
    - settings
    - vulnerability
    - vulnerability_detector
    - providers
'''
import pytest
from pathlib import Path

from wazuh_testing.constants.daemons import ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON
from wazuh_testing.constants.paths.logs import WAZUH_LOG_PATH
from wazuh_testing.utils.callbacks import generate_callback
from wazuh_testing.tools.monitors.file_monitor import FileMonitor
from wazuh_testing.utils.db_queries import cve_db
from wazuh_testing.utils.services import control_service
from wazuh_testing.utils.configuration import (get_test_cases_data, load_configuration_template,
                                               update_configuration_template)
from wazuh_testing.modules.modulesd.vulnerability_detector import patterns as cb
from wazuh_testing.modules.modulesd.configuration import MODULESD_DEBUG
from wazuh_testing.modules.monitord.configuration import MONITORD_ROTATE_LOG
from . import (TEST_CASES_PATH, CONFIGURATIONS_PATH, custom_rhel_oval_feed_path, custom_rhel_json_feed_path,
               debian_oval_feed_path, debian_json_feed_path)


pytest.skip("The tests will be deprecated, they test the old Vulnerability Detector.", allow_module_level=True)

# Variables
local_internal_options = {MODULESD_DEBUG: '2', MONITORD_ROTATE_LOG: '0'}
daemons_handler_configuration = {'daemons': [ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON]}
pytestmark = [pytest.mark.server]

# Configuration and cases data
configurations_path = Path(CONFIGURATIONS_PATH, 'configuration_multiple_provider_feeds.yaml')
cases_path = Path(TEST_CASES_PATH, 'cases_multiple_provider_feeds.yaml')

# Test configurations
configuration_parameters, configuration_metadata, test_case_ids = get_test_cases_data(cases_path)
configurations = load_configuration_template(configurations_path, configuration_parameters,
                                             configuration_metadata)
# Set offline custom feeds configuration
to_modify = ['CUSTOM_REDHAT_OVAL_FEED_PATH', 'CUSTOM_REDHAT_JSON_FEED_PATH', 'CUSTOM_DEBIAN_OVAL_FEED_PATH',
             'CUSTOM_DEBIAN_JSON_FEED_PATH']
new_values = [custom_rhel_oval_feed_path, custom_rhel_json_feed_path, debian_oval_feed_path, debian_json_feed_path]
configurations = update_configuration_template(configurations, to_modify, new_values)
configuration_metadata = update_configuration_template(configuration_metadata, to_modify, new_values)


@pytest.mark.tier(level=0)
@pytest.mark.parametrize('test_configuration, test_metadata', zip(configurations, configuration_metadata),
                         ids=test_case_ids)
def test_check_log_multiple_provider_feeds(test_configuration, test_metadata, set_wazuh_configuration,
                                           configure_local_internal_options, truncate_monitored_files,
                                           clean_cve_tables, daemons_handler):
    '''
    description: Check if the <path> and <os path=...> options work properly according to the configuration
                 and check there are no conflicts when reading the feeds and inserting them in the database.

    test_phases:
        - setup:
            - Set a custom Wazuh configuration, with custom feeds for OVAL and NVD.
            - Configure custom local_internal_options.
            - Truncate wazuh logs.
            - Restart wazuh-modulesd daemon to apply configuration changes.
        - test:
            - Check that the feeds (XML and JSON) are imported successfully in the log.
            - Check that at least one feed data has been inserted in the vulnerabilities DB tables.
        - teardown:
            - Truncate wazuh logs.
            - Restore initial configuration,and local_internal_options.
            - Restart modulesd to apply configuration.

    wazuh_min_version: 4.2.0

    tier: 0

    parameters:
        - test_configuration:
            type: dict
            brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture.
        - test_metadata:
            type: dict
            brief: Wazuh configuration metadata
        - set_wazuh_configuration:
            type: fixture
            brief: Set the wazuh configuration according to the configuration data.
        - configure_local_internal_options:
            type: fixture
            brief: Set local_internal_options configuration.
        - truncate_monitored_files:
            type: fixture
            brief: Truncate all the log files and json alerts files before and after the test execution.
        - clean_cve_tables:
            type: fixture
            brief: Clean all CVE tables.
        - daemons_handler:
            type: fixture
            brief: Restart the wazuh-modulesd daemon.

    assertions:
        - The feed has been fetched.
        - The database has been refreshed successfully.
        - The update of the feed has been finished successfully

    input_description:
        -  The `test_multiple_feeds_provider.yaml` file provides the module configuration for this test.

    expected_output:
        - 'Fetching .* from .*<oval_feed_path>'
        - 'Refresh of <provider_name> database finished'
        - 'The update of the <provider_name> feed finished'
    '''
    file_monitor = FileMonitor(WAZUH_LOG_PATH)

    # Check OVAL feed us updated
    callback = generate_callback(cb.FETCHING_FEED, replacement={"feed_path": test_metadata['oval_feed_path']})

    file_monitor.start(timeout=20, callback=callback)
    assert file_monitor.callback_result is not None, f"Expected '{cb.FETCHING_FEED}' event was not found."

    provider_name = test_metadata['provider_name']
    json_feed_path = test_metadata['json_feed_path']

    # Check processing feed logs (Redhat and Debian have differente order)
    if 'Debian' in provider_name:
        file_monitor.start(callback=generate_callback(cb.FETCHING_FEED,
                                                      replacement={"feed_path": json_feed_path}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.FETCHING_FEED}' event was not found."

        file_monitor.start(callback=generate_callback(cb.DATABASE_REFRESH_FINISHED,
                                                      replacement={"provider_name": provider_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.DATABASE_REFRESH_FINISHED}' event not found."

        file_monitor.start(callback=generate_callback(cb.FEED_UPDATE_FINISHED,
                                                      replacement={"provider_name": provider_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.FEED_UPDATE_FINISHED}' event not found."
    elif 'Red Hat' in provider_name:

        provider_json_name = test_metadata['provider_json_name']

        file_monitor.start(callback=generate_callback(cb.DATABASE_REFRESH_FINISHED,
                                                      replacement={"provider_name": provider_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.DATABASE_REFRESH_FINISHED}' event not found."

        file_monitor.start(callback=generate_callback(cb.FEED_UPDATE_FINISHED,
                                                      replacement={"provider_name": provider_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.FEED_UPDATE_FINISHED}' event not found."

        file_monitor.start(callback=generate_callback(cb.FETCHING_FEED,
                                                      replacement={"feed_path": json_feed_path}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.FETCHING_FEED}' event was not found."

        file_monitor.start(callback=generate_callback(cb.DATABASE_REFRESH_FINISHED,
                                                      replacement={"provider_name": provider_json_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.DATABASE_REFRESH_FINISHED}' event not found."

        file_monitor.start(callback=generate_callback(cb.FEED_UPDATE_FINISHED,
                                                      replacement={"provider_name": provider_json_name}))
        assert file_monitor.callback_result is not None, f"Expected '{cb.FEED_UPDATE_FINISHED}' event not found."
    else:
        raise ValueError(f"Unexpected {test_metadata['provider_name']} provider in the test case metadata list")

    # Vulnerabilities from OVAL and JSON feeds must be inserted in the corresponding tables of the DB
    assert cve_db.check_inserted_value_exists('VULNERABILITIES', 'CVEID', 'CVE-000')
    assert cve_db.check_inserted_value_exists('VULNERABILITIES_INFO', 'ID', 'CVE-000')
